/*
 * mana (library)
 * Copyright (c) 2003 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*!
 * @file
 * @brief	mana_actorクラスに関するヘッダーファイル
 *
 * このファイルはmana_actorクラスに関係するヘッダーファイルです。
 * mana_actorクラスは更新やリクエストなどの制御、外部関数の呼び出しなどの
 * 実行環境を表しています。
 *
 * @author	Shun Moriya <shun@mnu.sakura.ne.jp>
 */

#if !defined(___MANA_ACTOR_H___)
#define ___MANA_ACTOR_H___

#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

#if !defined(___MANA_FRAME_H___)
#include "mana_frame.h"
#endif
#if !defined(___MANA_HASH_H___)
#include "mana_hash.h"
#endif
#if !defined(___MANA_INFO_H___)
#include "mana_info.h"
#endif
#if !defined(___MANA_STACK_H___)
#include "mana_stack.h"
#endif
#if !defined(___MANA_STREAM_H___)
#include "mana_stream.h"
#endif
#include <stddef.h>

#define MANA_RETURN_VALUE_TYPE_INVALID	( 0)	/*!< @brief 戻り値：無効 */
#define MANA_RETURN_VALUE_TYPE_ACTOR	(-1)	/*!< @brief 戻り値：アクターへの参照 */
#define MANA_RETURN_VALUE_TYPE_INTEGER	(-2)	/*!< @brief 戻り値：整数 */
#define MANA_RETURN_VALUE_TYPE_FLOAT	(-3)	/*!< @brief 戻り値：小数 */
#define MANA_RETURN_VALUE_TYPE_STRING	(-4)	/*!< @brief 戻り値：文字列への参照 */

/*! @brief mana_actor_callback関数への命令タイプ */
typedef enum mana_file_callback_command
{
	MANA_FILE_COMMAND_CLOSE,					/*!< @brief ファイルを閉じます */
	MANA_FILE_COMMAND_IS_READING				/*!< @brief ファイルが読み込み中か取得します */
}mana_file_callback_command;

/*! @brief ファイル制御コールバック */
typedef void (mana_actor_file_callback)(mana_file_callback_command, void* parameter);

/*! @brief 割り込みテーブル */
typedef struct mana_interrupt
{
	struct mana_actor* sender;				/*!< @brief 要求したmana_actor オブジェクト */
	unsigned int address;						/*!< @brief 割り込み先アドレス */
	unsigned int return_address;				/*!< @brief リターンアドレス */
	int counter;								/*!< @brief 汎用カウンタ */
	int frame_pointer;							/*!< @brief フレームポインタ */
	int stack_pointer;							/*!< @brief スタックポインタ */
	void* file_callback_parameter;			/*!< @brief ファイル終了コールバックパラメータ */
#if !defined(NDEBUG)
	const char* action_name;					/*!< @brief 実行中のアクション名 */
#endif
	unsigned char flag;
	/*
	 * mana_actor :: flags
	 *
	 *| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
	 *	|	|	|	|	|	|	|	|
	 *	|	|	|	|	|	|	|	+-- MANA_INTERRUPT_FLAG_INITIALIZED
	 *	|	|	|	|	|	|	+------ MANA_INTERRUPT_FLAG_IS_IN_SYNC_CALL
	 *	|	|	|	|	|	+---------- MANA_INTERRUPT_FLAG_REPEAT
	 *	|	|	|	|	+-------------- MANA_INTERRUPT_FLAG_SUSPEND
	 *	|	|	|	+------------------ MANA_INTERRUPT_FLAG_SYNCHRONIZED
	 *	|	|	+----------------------
	 *	|	+--------------------------
	 *	+------------------------------
	 */
}mana_interrupt;

#define MANA_INTERRUPT_FLAG_INITIALIZED		(0x01)/*!< @brief 初期化済みフラグ */
#define MANA_INTERRUPT_FLAG_IS_IN_SYNC_CALL	(0x02)/*!< @brief 同期実行フラグ */
#define MANA_INTERRUPT_FLAG_REPEAT			(0x04)/*!< @brief リピートフラグ */
#define MANA_INTERRUPT_FLAG_SUSPEND			(0x08)/*!< @brief サスペンドフラグ */
#define MANA_INTERRUPT_FLAG_SYNCHRONIZED	(0x10)/*!< @brief 同期フラグ */

/*! @brief 戻り値 */
typedef struct mana_return_value
{
	union
	{
		int integer_value;						/*!< @brief 整数値 */
		float float_value;						/*!< @brief 実数値 */
		const char* string_value;				/*!< @brief 文字列 */
		void* pointer_value;					/*!< @brief 構造体 */
		struct mana_actor* actor_value;		/*!< @brief アクター */
	} values;
	int size;									/*!< @brief サイズ(pointer_value) */
}mana_return_value;

/*!
 * @brief	mana_actorクラス
 * mana_actorクラスはアクターを表しています。
 * C++でいうところのメンバー変数ですが、C言語なので全てpublicになっています。
 * 操作用の関数を用意しているので、それらの関数を利用して操作してください。
 */
typedef struct mana_actor
{
#if !defined(NDEBUG)
	char* name;													/*!< @brief アクター名 */
#endif
	struct mana* parent;										/*!< @brief 所属するManaオブジェクトへのポインタ */
	mana_frame frame;											/*!< @brief フレームメモリ */
	mana_stack stack;											/*!< @brief スタック */
	mana_hash actions;											/*!< @brief アクションHash */
	mana_interrupt interrupt[MANA_ACTOR_MAX_INTERRUPT_LEVEL];	/*!< @brief 割り込みテーブル */
	mana_return_value return_value;								/*!< @brief 戻り値 */
	void* request_callback_parameter;							/*!< @brief リクエストコールバック */
	void* rollback_callback_parameter;							/*!< @brief ロールバックコールバック */
	void* variable;												/*!< @brief インスタンス変数 */
	size_t variable_size;										/*!< @brief インスタンス変数のサイズ */
	unsigned int pc;											/*!< @brief プログラムカウンタ */
	unsigned char interrupt_level;								/*!< @brief 割り込みレベル */
	unsigned char flag;
	/*
	 * mana_actor :: flags
	 *
	 *| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
	 *	|	|	|	|	|	|	|	|
	 *	|	|	|	|	|	|	|	+-- MANA_ACTOR_FLAG_BATTLER
	 *	|	|	|	|	|	|	+------ MANA_ACTOR_FLAG_CHARACTER
	 *	|	|	|	|	|	+---------- MANA_ACTOR_FLAG_HALT
	 *	|	|	|	|	+-------------- MANA_ACTOR_FLAG_RUNNING
	 *	|	|	|	+------------------ MANA_ACTOR_FLAG_TOUCHED
	 *	|	|	+---------------------- MANA_ACTOR_FLAG_HIDED
	 *	|	+-------------------------- MANA_ACTOR_FLAG_REQUESTED
	 *	+------------------------------ MANA_ACTOR_FLAG_REFUSED
	 */
	unsigned short padding;
	unsigned int user_data;										/*!< @brief ユーザーデータ */
	void* user_pointer;											/*!< @brief ユーザーポインター */
}mana_actor;

#define MANA_ACTOR_FLAG_BATTLER		(0x01)		/*!< @brief 戦闘参加フラグ */
#define MANA_ACTOR_FLAG_CHARACTER	(0x02)		/*!< @brief キャラクターフラグ */
#define MANA_ACTOR_FLAG_HALT			(0x04)		/*!< @brief 停止フラグ */
#define MANA_ACTOR_FLAG_RUNNING		(0x08)		/*!< @brief 実行フラグ */
#define MANA_ACTOR_FLAG_TOUCHED		(0x10)		/*!< @brief 接触フラグ */
#define MANA_ACTOR_FLAG_HIDED			(0x20)		/*!< @brief 非表示フラグ */
#define MANA_ACTOR_FLAG_REQUESTED	(0x40)		/*!< @brief リクエストフラグ */
#define MANA_ACTOR_FLAG_REFUSED		(0x80)		/*!< @brief リクエスト禁止フラグ */

/*! @brief request / rollbackコールバック */
typedef int (mana_actor_callback)(mana_actor* actor, void* parameter);

/*! @brief 外部関数宣言用型 */
typedef void (mana_external_funtion_type)(mana_actor* actor);

/*! @brief mana_actor オブジェクトの生成 */
extern mana_actor* mana_actor_create(struct mana* parent, const size_t variable_size);

/*! @brief mana_actor オブジェクトのコピー */
extern mana_actor* mana_actor_clone(mana_actor* actor);

/*! @brief mana_actor オブジェクトの破棄 */
extern void mana_actor_destroy(mana_actor* self);

/*! @brief mana_actor オブジェクトのシリアライズ */
extern void mana_actor_serialize(mana_actor* self, mana_stream* stream);

/*! @brief mana_actor オブジェクトのデシリアライズ */
extern void mana_actor_deserialize(mana_actor* self, mana_stream* stream);

/*! @brief 経過時間を取得 */
extern float mana_actor_get_delta_time(void);

/*! @brief 経過時間を設定 */
extern void mana_actor_set_delta_time(float second);

/*! @brief 更新 */
extern int mana_actor_run(mana_actor* self);

/*! @brief 同期実行 */
extern mana_bool mana_sync_call(mana_actor* self, const int level, const char* action, mana_actor* sender);

/*! @brief 非同期実行 */
extern mana_bool mana_async_call(mana_actor* self, const int level, const char* action, mana_actor* sender);

/*! @brief リクエスト */
extern mana_bool mana_actor_request(mana_actor* self, const int level, const char* name, mana_actor* sender);

/*! @brief ロールバック */
extern void mana_actor_rollback(mana_actor* self, int level);

/*! @brief 再起動 */
extern void mana_actor_restart(mana_actor* self);

/*! @brief 名前を取得 */
extern const char* mana_actor_get_name(mana_actor* self);

/*! @brief アクションのプログラム開始アドレスを取得 */
extern unsigned int mana_actor_get_action(mana_actor* self, const char* name);

/*! @brief 汎用カウンターを取得 */
extern int mana_actor_get_counter(mana_actor* self);

/*! @brief 汎用カウンターを設定 */
extern void mana_actor_set_counter(mana_actor* self, const int counter);

/*! @brief 引数の数を取得 */
extern int mana_actor_get_argument_count(mana_actor* self);

/*! @brief 引数の数を取得 */
extern int mana_actor_get_argument_count_by_address(mana_actor* self, const unsigned int address);

/*! @brief 引数のサイズを取得 */
extern int mana_actor_get_argument_size(mana_actor* self, const unsigned int address);

/*! @brief 戻り値が存在するか調べる */
extern mana_bool mana_actor_has_return_value(mana_actor* self, const unsigned int address);

/*! @brief 整数型の引数を取得 */
extern int mana_actor_get_parameter_integer(mana_actor* self, const int value);

/*! @brief 実数型の引数を取得 */
extern float mana_actor_get_parameter_float(mana_actor* self, const int value);

/*! @brief 文字列型の引数を取得 */
extern const char* mana_actor_get_parameter_string(mana_actor* self, const int value);

/*! @brief アクター型の引数を取得 */
extern mana_actor* mana_actor_get_parameter_actor(mana_actor* self, const int value);

/*! @brief ポインター型の引数を取得 */
extern void* mana_actor_get_parameter_pointer(mana_actor* self, const int value);

/*! @brief ポインター型の引数を取得 */
extern void* mana_actor_get_parameter_address(mana_actor* self, const int value);

/*! @brief 整数型の戻り値を設定 */
extern void mana_actor_set_return_integer(mana_actor* self, const int value);

/*! @brief 実数型の戻り値を設定 */
extern void mana_actor_set_return_float(mana_actor* self, const float value);

/*! @brief 文字列型の戻り値を設定 */
extern void mana_actor_set_return_string(mana_actor* self, const char* string);

/*! @brief アクター型の戻り値を設定 */
extern void mana_actor_set_return_actor(mana_actor* self, mana_actor* actor);

/*! @brief ポインター型の戻り値を設定 */
extern void mana_actor_set_return_pointer(mana_actor* self, void* pointer);

/*! @brief データの戻り値を設定 */
extern void mana_actor_set_return_data(mana_actor* self, const void* pointer, const int size);

#if !defined(NDEBUG)
/*! @brief 実行中のアクション名を取得 */
const char* mana_actor_get_action_name(const mana_actor* self);

/*! @brief 実行中の外部関数名を取得 */
const char* mana_actor_get_function_name(const mana_actor* self);
#endif

/*! @brief mana_actor オブジェクトにアクションを登録(protected) */
extern void mana_actor_set_action(mana_actor* self, const char* name, unsigned char* address);

/*! @brief mana オブジェクトを取得します */
extern struct mana* mana_actor_get_parent(const mana_actor* self);

/*! @brief 初期化フラグを取得 */
extern mana_bool mana_actor_is_init(const mana_actor* self);

/*! @brief リピートフラグを取得 */
extern mana_bool mana_actor_is_repeat(const mana_actor* self);

/*! @brief 実行フラグを取得 */
extern mana_bool mana_actor_is_running(const mana_actor* self);

/*! @brief 実行中の命令を中断して次のフレームに再実行します */
extern void mana_actor_repeat(mana_actor* self, const mana_bool initial_complete);

/*! @brief 実行中の命令を中断して同じフレーム中に再実行します */
extern void mana_actor_again(mana_actor* self);

/*! @brief 実行停止 */
extern void mana_actor_halt(mana_actor* self);

/*! @brief 実行停止 */
extern void mana_actor_stop(mana_actor* self);

/*! @brief 次のフレームまで実行中断 */
extern void mana_actor_yield(mana_actor* self);

/*! @brief リクエストを許可 */
extern void mana_actor_comply(mana_actor* self);

/*! @brief リクエストを拒否 */
extern void mana_actor_refuse(mana_actor* self);

/*! @brief 優先度を取得 */
extern int mana_actor_get_interrupt_level(mana_actor* self);

/*! @brief 同期フラグを取得 */
extern mana_bool mana_actor_is_synchronized(mana_actor* self);

/*! @brief 同期フラグを設定 */
extern void mana_actor_set_synchronized(mana_actor* self, mana_bool synchronized);

/*! @brief 優先度付き同期フラグの設定 */
extern void mana_actor_set_synchronized_with_level(mana_actor* self, int level, mana_bool synchronized);

/*! @brief リソースデータの取得 */
extern void mana_actor_get_data(const mana_actor* self, const int resouce_id, const void** buffer, size_t* size);

/*! @brief ファイル読み込みコールバックの取得 */
extern mana_actor_file_callback* mana_actor_get_file_callback(void);

/*! @brief ファイル読み込みコールバックの設定 */
extern void mana_actor_set_file_callback(mana_actor_file_callback* function);

/*! @brief ファイル読み込みコールバックパラメーターの取得 */
extern void* mana_actor_get_file_callback_parameter(mana_actor* self, int level);

/*! @brief ファイル読み込みコールバックパラメーターの設定 */
extern void mana_actor_set_file_callback_parameter(mana_actor* self, int level, void* parameter);

/*! @brief リクエストコールバックの設定 */
extern void mana_actor_set_request_callback(mana_actor_callback* function);

/*! @brief リクエストコールバックパラメーターの設定 */
extern void mana_actor_set_request_callback_parameter(mana_actor* self, void* parameter);

/*! @brief ロールバックコールバックの設定 */
extern void mana_actor_set_rollback_callback(mana_actor_callback* function);

/*! @brief ロールバックコールバックパラメーターの設定 */
extern void mana_actor_set_rollback_callback_parameter(mana_actor* self, void* parameter);

/*!< @brief ユーザーデータの取得 */
extern unsigned int mana_actor_get_user_data(const mana_actor* self);

/*!< @brief ユーザーデータの設定 */
extern void mana_actor_set_user_data(mana_actor* self, unsigned int user_data);

/*!< @brief ユーザーポインターの取得 */
extern void* mana_actor_get_user_pointer(const mana_actor* self);

/*!< @brief ユーザーポインターの設定 */
extern void mana_actor_set_user_pointer(mana_actor* self, void* user_pointer);

#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif
